home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / ETC / UNIXCARK < prev    next >
Text File  |  1992-01-14  |  13KB  |  599 lines

  1. /* Original Header from BBC BASIC version.
  2.  
  3.    This program will unpack Spark or arc style archives on the BBC
  4.    and Archimedes. To produce an archive that can be unpacked using it
  5.    you must set arc or Spark to not use squashing.
  6.    Although you can use this on the Archie, a much better solution,
  7.    is to use !SparkPlug. If you have an Archie, and would like to make
  8.    your own archives and manipulate them in style from the desktop,
  9.    you need a copy of Spark. This is obtainable for M-#5.99 from:
  10.    David Pilling,
  11.    P.O. Box 22,
  12.    Thornton Cleveleys,
  13.    Blackpool.
  14.    FY5 1LR.
  15.  
  16.    You are encouraged to add your own bits to this program and pass it on.
  17.    If you do modify it, add your name and details below.
  18.  
  19.    V0.00 20th September 1989 -- David Pilling
  20.    V0.01 25th September 1989 -- Philip Colmer
  21.                                  Changed BASIC V usage to BASIC II
  22.    V0.02 21st February 1990  -- Philip Colmer
  23.                                  Improved support for DFS
  24.    V0.03 22nd April 1991     -- Philip Colmer
  25.                                  Fixed bugs in directory handling
  26.  
  27.  
  28.    This version, renamed Cark (for want of a better name !) is a port
  29.    of Bark to Unix C.  You are GREATLY encouraged to improve it...
  30.    my knowledge of C is very limited and I suspect that the coding
  31.    could be much better ! - Alun.
  32.  
  33.  
  34.    V0.01 4th  June  1991     -- Alun Jones
  35.                                  Ported (messily!) to Unix style C.    
  36.  
  37.    V0.02 2nd Dec 1991        -- Andy Duplain (duplain@rtf.bt.co.uk)
  38.                                    Further porting to 4.2BSD (and provision made
  39.                                 for System V).  Define either 'BSD' or 'SYSV'
  40.                                 when compiling.                               
  41.  
  42.    V0.03 17th Dec 1991        -- Andy Duplain (duplain@rtf.bt.co.uk)                           
  43.                 Fixed errors in function prototypes for PCC
  44.                 C compilers.                                               
  45.  
  46.    V0.04 20th Dec 1991        -- Andy Duplain (duplain@rtf.bt.co.uk)
  47.                    Changed '-t' option output from stderr to stdout.                                               
  48.                 
  49.    V0.05 8th Jan 1992        -- Andy Duplain (duplain@rtf.bt.co.uk)
  50.                    Added patch posted to NEWS by Martin Percival
  51.                 (martin@thed.uk22.bull.com) to unpack type 127 archives.
  52. */
  53.  
  54. #include <stdio.h>
  55.  
  56. #ifdef    BSD                        /* Berkeley */
  57. #    include <strings.h>
  58. #    define    remove    unlink            
  59. #    define    UNIX                                                   
  60. #    undef    SYSV
  61. #endif
  62.  
  63. #ifdef    SYSV                    /* System V */
  64. #    include <sys/types.h>
  65. #    include <sys/stat.h>
  66. #    include <string.h>
  67. #    include <stdlib.h> 
  68. #    define    remove     unlink
  69. #    define    UNIX
  70. #    undef    BSD
  71. #endif
  72.  
  73. #ifndef UNIX                    /* Not UNIX */
  74. #    include <string.h>
  75. #    include <stdlib.h>
  76. #endif
  77.  
  78. #define MAXCODE(n) ((1<<n)-1)
  79.  
  80. /* Used by many functions */
  81. static  FILE * fp,
  82.        *fo,
  83.        *logfile;
  84. static char rmask[9] = {
  85.     0, 1, 3, 7, 15, 31, 63, 127, 255
  86. };
  87.  
  88. static int  buf[128];
  89. static char filename[255];
  90. char    compname[270];            /* Ready for system() uncompress call */
  91. static int  isdir,
  92.             earc;
  93. static int  run,
  94.             c,
  95.             rc;
  96.  
  97. /* permissions of files, lengths, etc. */
  98. static long load,
  99.             exec,
  100.             attr,
  101.             type,
  102.             clen,
  103.             olen;
  104. static int  date,
  105.             time,
  106.             crc;
  107.  
  108. /* Used by uncrunch/getcode */
  109. static int  n_bits,
  110.             clear_flg,
  111.             maxcode,
  112.             free_ent,
  113.             offset,
  114.             size;
  115.  
  116. int            testonly = 0;    /* Used by -t option */
  117.  
  118. /* Used to guard function prototypes for PCC and ANSI compilers... */
  119.             
  120. #if defined(__STDC__) || defined(__cplusplus)
  121. # define P_(s) s
  122. #else
  123. # define P_(s) ()
  124. #endif
  125.  
  126. int main P_((int argc, char **argv));
  127. int rdhdr P_((void));
  128. long word P_((void));
  129. int dble P_((void));
  130. void unpack P_((char *root, char *file));
  131. void unstore P_((void));
  132. void unpck P_((void));
  133. void putc_ncr P_((int b));
  134. int get_c P_((void));
  135. void uncrunch P_((void));
  136. int getcode P_((void));
  137.  
  138. #undef P_
  139.  
  140. int     main (argc, argv)
  141. int     argc;
  142. char  **argv;
  143. {
  144.     char    cline[256],
  145.             fullname[256];
  146.     int     level = 0;
  147.     int     l[32];
  148.     l[0] = 0;
  149.     *fullname = 0;
  150.  
  151.     /* Wrong # args */
  152.     if (argc < 2) {
  153.            fprintf (stderr, "Usage : %s [-t] <filename>\n", *argv);
  154.           exit (1);
  155.     }                                                   
  156.                                          
  157.     /* Crappy option parsing... */
  158.     
  159.     if (argc == 3 && argv[1][0] == '-')
  160.     {
  161.         switch(argv[1][1])
  162.         {
  163.             case 't':            /* Test */
  164.                 testonly++;
  165.                 break;
  166.             default:
  167.                 fprintf(stderr, "Unknown option '-%c'\n", argv[1][1]);
  168.                 exit(1);
  169.         }                 
  170.         *++argv;
  171.     }
  172.  
  173.     /* Can't open file for reading */
  174.     if ((fp = fopen (*++argv, "r")) == NULL) {
  175.     fprintf (stderr, "\nCan't find file %s\n", *argv);
  176.     exit (1);
  177.     }
  178.  
  179.     /* Version number */
  180.     puts("Cark V0.05 January 1992, based on Bark V0.03");
  181.  
  182.     /* File types */ 
  183.     if (!testonly)
  184.         logfile = fopen ("settypes", "w");
  185.  
  186.     /* Main loop - rdhdr returns non-zero if EOF reached */
  187.     while (!rdhdr ()) {
  188.     /* End of top level dir */
  189.     if ((earc) && (level == 0))
  190.         break;
  191.  
  192.     /* New directory in archive */
  193.     if (isdir) {
  194.         l[level++] = strlen(fullname);/* Remember old pathname  */
  195.         strcat(fullname, filename);/* Add new name           */
  196.         if (!testonly) 
  197.         {
  198.                printf("Creating directory %s\n", fullname);
  199. #ifdef    UNIX     
  200.               mkdir(fullname, 0755);        /* Ignore error */
  201. #else    /* Not UNIX */
  202.               sprintf (cline, "mkdir %s\n", fullname);
  203.               system (cline);
  204. #endif    /* UNIX */                                       
  205.         }
  206.         else
  207.             printf("Directory %s\n", fullname);
  208.         strcat (fullname, "/");/* Add the dir. separator */
  209.     }
  210.     else
  211.         if (earc) {
  212.         fullname[l[--level]] = 0;/* Step back up a level   */
  213.         if (strlen (fullname) != 0)
  214.             printf ("Directory:   %s\n", fullname);
  215.         }
  216.         else {                                   
  217.             if (testonly)
  218.                 printf ("Testing file : %s%s ... ", fullname, filename);
  219.             else                
  220.                 printf ("Restoring file : %s%s ... ", fullname, filename);
  221.             unpack (fullname, filename);/* Not a dir, so a file   */
  222.         }
  223.     }
  224.     /* End of archive, so close files */
  225.     fclose (fp);
  226.     if (!testonly)
  227.         fclose (logfile);
  228.     exit (0);
  229. }
  230.  
  231.  
  232. /* Read header */
  233. int     rdhdr () {
  234.     int     i;
  235.  
  236.     /* archive flag */
  237.     if (getc (fp) != 26) {    /* Missing flag, try and find another */
  238.         fprintf (stderr, "Bad Header\n");
  239.         while ((i = getc (fp)) != 26)
  240.             if (i == EOF)
  241.             break;
  242.         if (i == EOF) {
  243.             return (1);
  244.         }
  245.     }
  246.  
  247.     /* Compression type */
  248.     type = getc (fp) & 0x7f;
  249.  
  250.     if (type == 0) {        /* End of archive */
  251.         earc = 1;
  252.         isdir = 0;
  253.         return (0);
  254.     }
  255.  
  256.     earc = 0;
  257.     for (i = 0; i <= 12; ++i) {    /* Get filename */
  258.         filename[i] = getc (fp);
  259.             if (filename[i] <= 32)
  260.                 filename[i] = 0;
  261.     }
  262.  
  263.     clen = word ();        /* Compressed length                   */
  264.     date = dble ();        /* File creation date                  */
  265.     time = dble ();        /* File creation time                  */
  266.     crc = dble ();        /* crc byte - unchecked                */
  267.     if (type > 1)
  268.         olen = word ();    /* Compressed, so find original length */
  269.     else
  270.         olen = clen;       /* Not compressed                      */
  271.     load = word ();        /* Load address                        */
  272.     exec = word ();        /* Execution address                   */
  273.     attr = word ();        /* File attributes                     */
  274.     if ((type == 2) && ((load & 0xffffff00) == 0xfffddc00))
  275.         isdir = 1;        /* File is a directory                 */
  276.     else
  277.         isdir = 0;        /* No it aint !                        */
  278.     return (0);
  279. }
  280.  
  281.  
  282. /* Get 4 bytes */
  283. long    word () {
  284.     long    n;
  285.     n = getc (fp);
  286.     n |= (getc (fp) << 8);
  287.     n |= (getc (fp) << 16);
  288.     n |= (getc (fp) << 24);
  289.     return (n);
  290. }
  291.  
  292.  
  293. /* Get 2 bytes */
  294. int     dble () {
  295.     int     i;
  296.     i = getc (fp);
  297.     i |= (getc (fp) << 8);
  298.     return (i);
  299. }
  300.  
  301.  
  302. /* Unpack file */
  303. void unpack (root, file)
  304. char   *root,
  305.        *file;
  306. {
  307.     char    fullpath[255];
  308.     int     i;
  309.  
  310.  
  311.     /* Open file and report any error */
  312.     sprintf (fullpath, "%s%s", root, file);
  313.     if (!testonly && type != 127)        /* type 127 uncompressed seperately */
  314.         if ((fo = fopen (fullpath, "w")) == NULL) {
  315.             fprintf (stderr, "Can't open file %s\n", fullpath);
  316.             exit (1);
  317.         }
  318.  
  319.     /* Decide appropriate compression action */
  320.     switch (type) {
  321.     case 1: 
  322.     case 2: 
  323.         /* Not compressed */
  324.         unstore ();
  325.         break;
  326.     case 8: 
  327.         /* Crunched */
  328.         uncrunch ();
  329.         break;
  330.     case 3: 
  331.         /* I dunno */
  332.         unpck ();
  333.         break;
  334.     case 127:        /* Compressed file, save as *.Z and use compress utility */
  335.         if (testonly)
  336.             puts("unix compress file");
  337.         else
  338.             puts("Uncompressing");
  339.         strcpy(compname, "compress -d ");    /* Perferable to uncompress */
  340.         strcat(fullpath, ".Z");
  341.         strcat(compname, fullpath);
  342.         if (!testonly)
  343.         {
  344.             if ((fo = fopen(fullpath, "w")) == NULL)
  345.             {
  346.                 fprintf(stderr, "Can't open file %s\n", fullpath); 
  347.                 exit(1);
  348.             }
  349.         
  350.             putc(31, fo);                /* Write magic header for compress file */
  351.             putc(157, fo);
  352.             putc((getc(fp) + 0x80), fo); /* and adjust byte 1 of file to be UNIX
  353.                                 bit indicator */
  354.             while (clen-- > 1)
  355.                 putc(getc(fp), fo);        /* Copy bytes (-1) */
  356.             
  357.             fclose(fo);
  358.  
  359.             if (system(compname))        /* Do the uncompress */
  360.             {
  361.                    fprintf(stderr, "%s failed!\n", compname);
  362.                    exit(1);
  363.             }
  364.         }    
  365.         else                            /* Testing only */
  366.             while(clen--)
  367.                 getc(fp);                /* Throw away */
  368.                 
  369.         break;
  370.               
  371.     default: 
  372.         {                           
  373.         if (!testonly)
  374.             fprintf (stderr, "Can't unpack %s - compression type %d\n", file, type);
  375.         else
  376.             printf("Can't unpack, compression type %d\n", type);
  377.         /* Skip to end of file */
  378.         for (i = 1; i <= clen; ++i)
  379.             getc (fp);
  380.         /* Remove output file */
  381.         if (!testonly)
  382.             remove (fullpath);
  383.         }
  384.     }
  385.         
  386.     if (!testonly && type != 127)
  387.         fclose (fo);
  388.     /* Save appropriate SYS "OS_File" call to set catalogue info */
  389.     if (!testonly)
  390.     {
  391.         fprintf (logfile, "SYS %cOS_File%c, 1, %c", 34, 34, 34);
  392.         for (i = 0; root[i] != 0; ++i)
  393.         if (root[i] == '/')
  394.             putc ('.', logfile);
  395.         else
  396.             putc (root[i], logfile);
  397.         fprintf (logfile, "%s%c, &%x, &%x,, &%x\n", file, 34, load, exec, attr);
  398.     }
  399. }
  400.  
  401.  
  402. /* No compression */
  403. void unstore () {
  404.     int     i;
  405.     putchar('\n');
  406.     for (i = 0; i < clen; ++i)
  407.         if (testonly)
  408.             getc(fp);
  409.         else
  410.             putc (getc (fp), fo);
  411. }
  412.  
  413.  
  414. /* Looks like run length of some sort to me */
  415. void unpck () {
  416.     int     i;
  417.     run = 0;
  418.     c = 0;                  
  419.     if (testonly)
  420.         putchar('\n');
  421.     else
  422.         puts("Unpacking");
  423.     for (i = 0; i < clen; ++i)
  424.         putc_ncr (getc (fp));
  425. }
  426.  
  427.  
  428. /* Dunno */
  429. void putc_ncr (b)
  430. int     b;
  431. {
  432.     int     k;
  433.         
  434.     if (testonly)
  435.         return;
  436.         
  437.     if (c == 1) {
  438.         if (b == 0) {
  439.                putc (0x90, fo);
  440.             c = 0;
  441.             return;
  442.         }
  443.         else {
  444.             for (k = 1; k < b; ++k)
  445.             putc (run, fo);
  446.             c = 0;
  447.             return;
  448.         }
  449.     }
  450.     if (b == 0x90) {
  451.         c = 1;
  452.         return;
  453.     }
  454.     run = b;
  455.     putc (run, fo);
  456. }
  457.  
  458.  
  459. int     get_c () {
  460.     if      (rc > 0) {
  461.         --rc;
  462.         return (getc (fp));
  463.     }
  464.     else
  465.         return (-1);
  466. }
  467.  
  468.  
  469. /* Crunched */
  470. void uncrunch () {
  471.     int     i,
  472.             finchar,
  473.             incode,
  474.             code,
  475.             oldcode;
  476.     int     stack[4096],
  477.            *stackp;
  478.     int     suffix[4096];
  479.     int     prefix[4096];
  480.            
  481.     if (testonly)
  482.         putchar('\n');
  483.     else
  484.         puts("Uncrunching");
  485.         
  486.     c = 0;
  487.     offset = 0;
  488.     size = 0;
  489.     rc = clen;
  490.     code = get_c ();
  491.     if (code != 12) {
  492.         fprintf (stderr, "Can't unpack file - wrong number of bits\n");
  493.         exit (1);
  494.     }
  495.     n_bits = 9;
  496.     clear_flg = 0;
  497.     maxcode = MAXCODE (n_bits);
  498.     for (i = 0; i <= 256; ++i)
  499.         prefix[i] = 0;
  500.     for (code = 0; code < 256; ++code)
  501.         suffix[code] = code;              
  502.     free_ent = 257;
  503.     oldcode = getcode ();
  504.     finchar = oldcode;
  505.     if (oldcode == -1)
  506.         return;
  507.     putc_ncr (finchar);
  508.     stackp = stack;
  509.  
  510.     while (1) {
  511.         code = getcode ();
  512.         if (code < 0)
  513.             return;
  514.         if (code == 256) {
  515.             for (i = 0; i <= 256; ++i)
  516.                 prefix[i] = 0;
  517.             clear_flg = 1;
  518.             free_ent = 256;
  519.             code = getcode ();
  520.             if (code == -1)
  521.                 return;
  522.         }
  523.         incode = code;
  524.         if (code >= free_ent) {
  525.             *stackp++ = finchar;
  526.             code = oldcode;
  527.         }
  528.         while (code >= 256) {
  529.             *stackp++ = suffix[code];
  530.             code = prefix[code];
  531.         }
  532.         finchar = suffix[code];
  533.         *stackp++ = finchar;
  534.         while (stackp > stack)
  535.             putc_ncr (*--stackp);
  536.             code = free_ent;
  537.             if (code < 4096) {
  538.             prefix[code] = oldcode;
  539.             suffix[code] = finchar;
  540.             free_ent = code + 1;
  541.         }
  542.         oldcode = incode;
  543.     }
  544. }
  545.  
  546. int     getcode () {
  547.     int     code,
  548.             temp,
  549.             r_off,
  550.             bits;
  551.     int     bp = 0;
  552.  
  553.     if ((clear_flg > 0) || (offset >= size) || (free_ent > maxcode)) {
  554.         if (free_ent > maxcode) {
  555.             ++n_bits;
  556.             if (n_bits == 12)
  557.                 maxcode = 4096;
  558.             else
  559.                 maxcode = MAXCODE (n_bits);
  560.         }
  561.         if (clear_flg > 0) {
  562.                n_bits = 9;
  563.                maxcode = MAXCODE (n_bits);
  564.             clear_flg = 0;
  565.            }
  566.          for (size = 0; size < n_bits; ++size) {
  567.             code = get_c ();
  568.             if (code == -1) {
  569.                  temp = size;
  570.                     size = n_bits;
  571.             }
  572.              else
  573.                   buf[size] = code;
  574.           }
  575.         if (size == (n_bits + 1)) {
  576.             size = temp;
  577.             if (size <= 0)
  578.                    return (-1);
  579.         }
  580.         offset = 0;
  581.          size = (size << 3) - (n_bits - 1);
  582.     }
  583.     r_off = offset;
  584.     bits = n_bits;
  585.     bp += r_off >> 3;
  586.     r_off = r_off & 7;
  587.     code = buf[bp++] >> r_off;
  588.     bits = bits - 8 + r_off;
  589.     r_off = 8 - r_off;
  590.     if (bits >= 8) {
  591.          code = code | (buf[bp++] << r_off);
  592.          r_off += 8;
  593.          bits -= 8;
  594.     }
  595.     code = code | ((buf[bp] & rmask[bits]) << r_off);
  596.     offset += n_bits;
  597.     return (code & 4095);
  598. }
  599.